/*************************************************************************************
**																					**
**	atProcessor.c		Si1000 processor (8051 derivative							**
** 																					**
**************************************************************************************
**																					**
** Written By:	Steve Montgomery													**
**				Digital Six Laboratories LLC										**
** (c)2012,2013,2104 Digital Six Labs, All rights reserved							**
**																					**
**************************************************************************************/
//
// Revision History
//
// Revision		Date	Revisor		Description
// ===================================================================================
// ===================================================================================


#include "..\..\SourceCode\Radio\Sx1272\radioapi.h"
#include "..\..\SourceCode\OpenRF_MAC\openrf_mac.h"
#include "atProcessor.h"



#define kATBufferSize 40
tAtStates _atState;
U8 _atBuffer[kATBufferSize];
U8 _bufPtr = 0;
U8 _foundA = 0;
U8 _foundT = 0;
U8 _commandCount;
U8 _maxCommandSize;
U8 _bufCount = 0;
U8 *_commands[32];
U8 _consumeBytes=0;
tCommandCallback _commandCallbacks[32];
tCommandCallback _errorCallback;
tCommandCallback _consumeCallback;

void ProcessATCommand();
tAtStates ATGetState()
{
	return _atState;
}
void ATExitCommandMode()
{
	_atState = kDisabled;
}
void ATInitialize(tCommandCallback errorCallback, tCommandCallback consumeCallback, U8 consume)
{
	U8 i;
	_consumeBytes = consume;
	_errorCallback = errorCallback;
	_consumeCallback = consumeCallback;
	_atState = kDisabled;
	_bufPtr=0;
	_bufCount = 0;
	_foundA=0;
	_foundT = 0;
	_commandCount=0;

}
void ATRegisterCommand(tAtCommand command)
{
	_commands[_commandCount] = command.command;
	_commandCallbacks[_commandCount] = command.callback;
	_commandCount=_commandCount+1;
}
void ATProcess()
{
	U8 ch;
	switch(_atState)
	{
		case kDisabled:
			if(BufferCountUART1()>0)
			{
				ch=Uart1PeekByte();
				if(ch=='+')
				{
					_atState=kPlus1;
					ReadCharUART1();
				}
				else
					if(_consumeBytes)
						_consumeCallback();
						// consume bytes... no one else needs them.
						//ReadCharUART1();
			}
			break;
		case kPlus1:
			if(BufferCountUART1()>0)
			{
				ch=Uart1PeekByte();
				if(ch=='+')
				{
					_atState=kPlus2;
					ReadCharUART1();
				}
				else
				{
					_atState=kDisabled;
					if(_consumeBytes)
						// consume bytes... no one else needs them.
						ReadCharUART1();
				}
			}
			break;
		case kPlus2:
			if(BufferCountUART1()>0)
			{

				ch=Uart1PeekByte();
				if(ch=='+')
				{
					ReadCharUART1();
					_atState=kEnabled;
					WriteCharUART1('O');
					WriteCharUART1('K');
					WriteCharUART1(0x0a);
					WriteCharUART1(0x0d);
				}
				else
				{
					_atState=kDisabled;
					if(_consumeBytes)
						ReadCharUART1();
				}
			}
			break;
		case kEnabled:
			ProcessATCommand();
			break;
	}
}
U8 Compare(U8 *cmdToCompare)
{
	U8 bp=0;
	U8 cnt=0;
	U8 *ptr = cmdToCompare;
	// cycle through string and compare to buffer
	while(*ptr!=0)
	{
		if(*ptr++ != _atBuffer[bp++])
			return 0;
		cnt++;
	}
	// if we found our command, we need to update bufPtr so it points to the next spot in the buffer after the last command character
	_bufPtr = bp;
	return cnt;
}
void ProcessCommands(U8 ch)
{
	U8 i,count,goodFormat=0;

	if((ch==0x0a) || (ch==0x0d))
	{
		_bufCount = _bufPtr;

		// in here, we have received the terminal character so we need to see if we can process the command.
		for(i=0;i<_commandCount;i++)
		{
			count = Compare(_commands[i]);
			if(count)
			{
				_commandCallbacks[i]();
				i=_commandCount;
				goodFormat=1;
			}
		}
		_foundA = 0;
		_foundT = 0;
		_bufPtr = 0;
		_bufCount=0;
		if(!goodFormat)
		{
			// Unrecognized command
			_errorCallback();
		}
	}
	else
	{
		// only put the char in the buffer if the buffer is not overflowing.  Otherwise, ignore it unless it is a terminal character

		if(_bufPtr<kATBufferSize)
			_atBuffer[_bufPtr++]=ch;
	}
}

void ProcessATCommand()
{
	U8 ch;
	U8 count;
	U8 i;
	// first, load all the characters we can into the buffer
	//
	count = BufferCountUART1();
	while(count--)
	{
		ch=ReadCharUART1();
		if((ch>='a') && (ch<='z'))
				ch-=('a'-'A');
		if(!_foundA)
		{
			if(ch=='A')
			{
				_foundA=1;
			}
			// we should never see a terminal character when we are looking for an A
			else if((ch==0x0a) || (ch==0x0d))
				_errorCallback();
		}
		else if( !_foundT)
		{
			if(ch=='T')
			{
				_foundT=1;
				_bufPtr=0;
				// salt the buffer.  This ensures that no old data can be used
				_atBuffer[0]=0;
			}
			// we should never see a terminal character when we are looking for an T
			else if((ch==0x0a) || (ch==0x0d))
			{
				_errorCallback();
				_foundA=0;
			}

		}
		else
		{

			if(_foundT)
				ProcessCommands(ch);
		}
	}
}
U8 IsATBufferNotEmpty()
{
	if(_bufCount>_bufPtr)
		return 1;

	return 0;
}
U8 GetATBufferCharacter()
{
	return _atBuffer[_bufPtr++];
}
void ExitCommandMode()
{
	_atState = kDisabled;
}
U8 IsInCommandMode()
{
	return _atState!=kDisabled;
}
U16 parseHexU16( U8 *str )
{
    U16 value = 0;


    while(*str!=0x00)
    {
		switch( *str )
		{
			case '0': case '1': case '2': case '3': case '4':
			case '5': case '6': case '7': case '8': case '9':
				value = value << 4 | ((*str-'0') & 0xf);
				break;
			case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
				value = value << 4 | (10 + (*str-'A') & 0xf);
				break;
			case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
				value = value << 4 | (10 + (*str-'a') & 0xf);
				break;
			default:
				return value;
		}
		str++;
    }
    return value;
}
U8 ATGetU16(U16 *val)
{
	U8 str[5];
	U8 i;

	for(i=0;(i<4 && IsATBufferNotEmpty());i++)
	{
		if(IsATBufferNotEmpty())
			str[i] = GetATBufferCharacter();
	}
	str[i]=0;
	*val= parseHexU16(&str[0]);
	return i;
}
U8 ATGetU16FromStream(U16 *val, U8 *stream)
{
	U8 str[5];
	U8 i;

	for(i=0;i<4;i++)
	{
		str[i] = *stream++;
	}
	str[i]=0;
	*val= parseHexU16(&str[0]);
	return i;
}
U32 parseHexU32( U8 *str )
{
    U32 value = 0;


    while(*str!=0x00)
    {
		switch( *str )
		{
			case '0': case '1': case '2': case '3': case '4':
			case '5': case '6': case '7': case '8': case '9':
				value = value << 4 | ((*str-'0') & 0xf);
				break;
			case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
				value = value << 4 | (10 + (*str-'A') & 0xf);
				break;
			case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
				value = value << 4 | (10 + (*str-'a') & 0xf);
				break;
			default:
				return value;
		}
		str++;
    }
    return value;
}
U8 ATGetU32(U32 *val)
{
	U8 str[9];
	U8 i;
	for(i=0;(i<8 && IsATBufferNotEmpty());i++)
	{
		if(IsATBufferNotEmpty())
			str[i] = GetATBufferCharacter();
	}
	str[i]=0;
	*val= parseHexU32(&str[0]);
	return i;
}
U8 ATGetU32FromStream(U32 *val, U8 *stream)
{
	U8 str[9];
	U8 i;
	for(i=0;i<8 ;i++)
	{
		str[i] = *stream++;
	}
	str[i]=0;
	*val= parseHexU32(&str[0]);
	return i;
}
U8 parseHexU8( U8 *str )
{
    U8 value = 0;

    while(*str!=0x00)
    {
		switch( *str )
		{
			case '0': case '1': case '2': case '3': case '4':
			case '5': case '6': case '7': case '8': case '9':
				value = value << 4 | ((*str-'0') & 0xf);
				break;
			case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
				value = value << 4 | (10 + (*str-'A') & 0xf);
				break;
			case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
				value = value << 4 | (10 + (*str-'a') & 0xf);
				break;
			default:
				return value;
		}
		str++;
    }
    return value;
}
U8 ATGetU8(U8 *val)
{
	U8 str[3];
	U8 i,bo;

	for(i=0;(i<2 && IsATBufferNotEmpty());i++)
	{
		bo=IsATBufferNotEmpty();
		if(bo)
			str[i] = GetATBufferCharacter();
	}
	str[i]=0;
	*val= parseHexU8(&str[0]);
	return i;
}
U8 ATGetU8FromStream(U8 *val, U8 *stream)
{
	U8 str[3];
	U8 i,bo;

	for(i=0;i<2;i++)
	{
		str[i] = *stream++;
	}
	str[i]=0;
	*val= parseHexU8(&str[0]);
	return i;
}
